/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.buffer;

import com.inspur.edp.bef.core.be.BeBufferChangeManager;
import com.inspur.edp.bef.core.be.IBeBufferChangeManager;
import com.inspur.edp.commonmodel.core.session.distributed.RootEditToken;
import com.inspur.edp.bef.core.session.transaction.IBefTransactionItem;
import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.entity.accessor.base.IAccessor;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.entity.IEntityData;
import java.util.List;
import java.util.Map.Entry;

public class TransBeBufferChangeManager implements IBeBufferChangeManager
{
  private BeBufferChangeManager bottom;
  public TransBeBufferChangeManager(BeBufferChangeManager bottom)
  {
    this.bottom = bottom;
  }

  public final IAccessor accept(String dataId, int level, IChangeDetail change)
  {
    return ((IBeBufferChangeManager)bottom).accept(dataId, level, change);
  }

  public final void acceptChange(String id, int level)
  {
    ((IBeBufferChangeManager)bottom).acceptChange(id, level);
  }

  public final IAccessor acceptCurrent(String id) {
    IChangeDetail change = bottom.getCurrentChange(id);
    addUndoLog(id, change, getTransactionData(id));
    addChangesetBackup(id);
    return bottom.acceptCurrent(id);
  }

  public final void acceptCurrentTemplateChange(String id)
  {
    bottom.acceptCurrentTemplateChange(id);
  }

  public final void acceptListenerChange(String ID)
  {
    bottom.acceptListenerChange(ID);
  }

  public final IAccessor acceptTemplateCurrentChange(String id, IChangeDetail change)
  {
    return bottom.acceptTemplateCurrentChange(id, change);
  }

  public final IAccessor acceptTransaction(String id)
  {
    return bottom.acceptTransaction(id);
  }

  public final void acceptTransactionChange(String id)
  {
    bottom.acceptTransactionChange(id);
  }

  public final void appendCurrentTemplateChange(IChangeDetail change)
  {
    bottom.appendCurrentTemplateChange(change);
  }

  public final IAccessor createCurrentBuffer(IEntityData data)
  {
    return bottom.createCurrentBuffer(data);
  }

  public final IAccessor getBuffer(String dataId, int level)
  {
    return ((IBeBufferChangeManager)bottom).getBuffer(dataId, level);
  }

  public final IAccessor getBuffer(String dataId)
  {
    return ((IBeBufferChangeManager)bottom).getBuffer(dataId);
  }

  public final IChangeDetail getChange(String id, int level)
  {
    return ((IBeBufferChangeManager)bottom).getChange(id, level);
  }

  public final IChangeDetail getCurrentChange(String id)
  {
    return bottom.getCurrentChange(id);
  }

  public final IEntityData getCurrentData(String dataId)
  {
    return bottom.getCurrentData(dataId);
  }

  public final IChangeDetail getCurrentTemplateChange(String id)
  {
    return bottom.getCurrentTemplateChange(id);
  }

  public final IChangeDetail getListenerChange(String id)
  {
    return bottom.getListenerChange(id);
  }

  public final IEntityData getOriginalData(String dataId)
  {
    return bottom.getOriginalData(dataId);
  }

  public final IChangeDetail getTransactionChange(String id)
  {
    return bottom.getTransactionChange(id);
  }

  public final IEntityData getTransactionData(String dataId)
  {
    return bottom.getTransactionData(dataId);
  }

  public final IAccessor initBufferByBaseLevel(String id, int level, boolean isReadonly)
  {
    return ((IBeBufferChangeManager)bottom).initBufferByBaseLevel(id, level, isReadonly);
  }

  public final IAccessor initBufferByLevel(IEntityData data, int level, boolean isReadonly)
  {
    return ((IBeBufferChangeManager)bottom).initBufferByLevel(data, level, isReadonly);
  }

  public final IAccessor initBuffer_ZeroLevel(IEntityData data, boolean isReadonly)
  {
    return ((IBeBufferChangeManager)bottom).initBuffer_ZeroLevel(data, isReadonly);
  }

  public final IEntityData initCurrentBuffer(String id)
  {
    return bottom.initCurrentBuffer(id);
  }

  public final void initCurrentTemplateChange(IChangeDetail change)
  {
    bottom.initCurrentTemplateChange(change);
  }

  public final void initListenerChange(IChangeDetail change)
  {
    bottom.initListenerChange(change);
  }

  public final IEntityData initTransactionBuffer(String id)
  {
    return bottom.initTransactionBuffer(id);
  }

  public final IAccessor reject(String dataId, int level, IChangeDetail change)
  {
    return ((IBeBufferChangeManager)bottom).reject(dataId, level, change);
  }

  public final IAccessor rejectCurrent(String id)
  {
    return bottom.rejectCurrent(id);
  }

  public final void rejectCurrentChange(String id)
  {
    bottom.rejectCurrentChange(id);
  }

  public final void rejectCurrentTemplateChange(String id)
  {
    bottom.rejectCurrentTemplateChange(id);
  }

  public final void rejectTransaction(String id, RefObject<IEntityData> current, RefObject<IEntityData> transaction)
  {
    getUndoLog().remove(id);
    bottom.rejectTransaction(id, current, transaction);
  }

  @Override
  public void clearChange() {
    bottom.clearChange();
  }

//  @Override
//  public boolean isEmpty(String id) {
//    return bottom.isEmpty(id);
//  }

  public final void rejectBufferZeroLevel(String id)
  {
    ((IBeBufferChangeManager)bottom).rejectBufferZeroLevel(id);
  }

  @Override
  public void remove(String dataId) {
    bottom.remove(dataId);
  }

///#region Transaction
  //buffer的回滚根据变更集做反向操作
  private java.util.Map<String, IChangeDetail> privateUndoLog	= new java.util.HashMap<String, IChangeDetail>();
  public final java.util.Map<String, IChangeDetail> getUndoLog()
  {
    return privateUndoLog;
  }

  private void addUndoLog(String id, IChangeDetail tranChange, IEntityData entityData)
  {
    IChangeDetail existing = getUndoLog().get(id);
    IChangeDetail reverseChange = UndoChangeDetailMerger.getInstance().buildUndoChange(tranChange, entityData, existing);
    if (reverseChange == null) {
      getUndoLog().remove(id);
    }
    else {
      getUndoLog().put(id, reverseChange);
    }
  }

  //变更集的回滚采取复制的方式, 原因:修改删除场景无法正确回滚,采用回滚是基于修改是少量的而数据是大量的假设, 所以变更集的复制不会带来问题
  private java.util.Map<String, IChangeDetail> privateChangesetBackup	= new java.util.HashMap<String, IChangeDetail>();
  public final java.util.Map<String, IChangeDetail> getChangesetBackup()
  {
    return privateChangesetBackup;
  }

  private void addChangesetBackup(String id)
  {
    if (getChangesetBackup().containsKey(id))
    {
      return;
    }
    IChangeDetail tranChange = getTransactionChange(id);
    getChangesetBackup().put(id, tranChange != null ? tranChange.clone() : null);
  }

  public final void commit(IBefTransactionItem upper) {
    TransBeBufferChangeManager up = (TransBeBufferChangeManager)upper;
    if(!up.getUndoLog().isEmpty()) {
      if(privateUndoLog.isEmpty()) {
        privateUndoLog = up.getUndoLog();
      } else {
        for (Entry<String, IChangeDetail> entry : up.getUndoLog().entrySet()) {
          privateUndoLog.putIfAbsent(entry.getKey(),entry.getValue());//TODO:两方都存在的回滚变更应该进行合并;
        }
      }
    }
    if(!up.getChangesetBackup().isEmpty()) {
      if(privateChangesetBackup.isEmpty()) {
        privateChangesetBackup = up.getChangesetBackup();
      } else {
        for (Entry<String, IChangeDetail> entry : up.getChangesetBackup().entrySet()) {
          privateChangesetBackup.putIfAbsent(entry.getKey(), entry.getValue());
        }
      }
    }
  }

  public IBefTransactionItem begin() {return new TransBeBufferChangeManager(bottom);}

  @Override
  public void endEdit(RootEditToken token) {

  }

  @Override
  public void beginEdit(RootEditToken token) {

  }

  @Override
  public void notifySave() {
    bottom.notifySave();
  }

  public void notifyReset() {
    bottom.notifyReset();
  }

  public final void rollBack() {
    bottom.innerRollBack(getUndoLog(), getChangesetBackup());
  }

  public  void recover(List<IChangeDetail> changes) {
    throw new RuntimeException();
  }

}
